Imports System
Imports System.IO
Imports System.Text
Imports System.Security.Cryptography

Namespace Cryptography

    Public Class Crypto
        Implements IDisposable

        Private UTF8 As UTF8Encoding
        Private TDESProvider As TripleDESCryptoServiceProvider
        Private cryptoTransformE As ICryptoTransform
        Private cryptoTransformD As ICryptoTransform

        Private key(15) As Byte
        'TODO: Change IV on non-public release
        Private iv() As Byte = {65, 110, 68, 26, 69, 178, 200, 219}

        Public Sub New(ByVal cryptokey As String)

            Dim i As Integer

            For i = 1 To key.Length
                key(i - 1) = Asc(Mid(cryptokey, i, 1))
            Next

            UTF8 = New UTF8Encoding()
            TDESProvider = New TripleDESCryptoServiceProvider()
            cryptoTransformE = TDESProvider.CreateEncryptor(key, iv)
            cryptoTransformD = TDESProvider.CreateDecryptor(key, iv)

        End Sub

        Public Sub New(ByVal cryptokey() As Byte)

            If cryptokey.GetLowerBound(0) = 0 And cryptokey.GetUpperBound(0) = 15 Then
                cryptokey.CopyTo(key, 0)
            Else
                Throw New ArgumentException("cryptokey must be an array of 16 bytes i.e dim key(15) as byte")
            End If

            UTF8 = New UTF8Encoding()
            TDESProvider = New TripleDESCryptoServiceProvider()
            cryptoTransformE = TDESProvider.CreateEncryptor(key, iv)
            cryptoTransformD = TDESProvider.CreateDecryptor(key, iv)

        End Sub

        Public Shared Function BytesToHex(ByRef bytes() As Byte) As String

            Dim i As Integer
            Dim tmp As String
            Dim str As String = ""

            For i = 0 To bytes.Length - 1
                tmp = Hex(bytes(i))
                If Len(tmp) < 2 Then
                    str &= "0" & tmp
                Else
                    str &= tmp
                End If
            Next

            Return str

        End Function

        Public Shared Function HexToBytes(ByVal str As String) As Byte()

            Dim i As Integer
            Dim tmp As String
            Dim bytes((Str.Length / 2) - 1) As Byte

            For i = 1 To (str.Length / 2)
                tmp = Mid(str, ((i - 1) * 2) + 1, 2)
                bytes(i - 1) = Convert.ToByte(tmp, 16)
            Next i

            Return bytes

        End Function

        Public Function Encrypt(ByVal plainText As String) As String
            ' Use the GetByte.UTF8Encoding method to transform the plainText into a Byte array.
            Dim inputInBytes() As Byte = UTF8.GetBytes(plainText)

            ' All cryptographic functions need a stream to output the
            ' encrypted information. Here we declare a memory stream
            ' for this purpose.
            Dim encryptedStream As MemoryStream = New MemoryStream()
            Dim cryptStream As CryptoStream = New CryptoStream(encryptedStream, cryptoTransformE, CryptoStreamMode.Write)

            ' Write the encrypted information to the stream. Flush the information
            ' when done to ensure everything is out of the buffer.
            cryptStream.Write(inputInBytes, 0, inputInBytes.Length)
            cryptStream.FlushFinalBlock()
            encryptedStream.Position = 0

            ' Read the stream back into a Byte array and return it to the calling
            ' method.
            Dim result(encryptedStream.Length - 1) As Byte
            encryptedStream.Read(result, 0, encryptedStream.Length)
            cryptStream.Close()
            encryptedStream.Close()

            Return UTF8.GetString(result)

        End Function

        Public Function EncryptBytes(ByVal inputInBytes() As Byte) As Byte()

            ' All cryptographic functions need a stream to output the
            ' encrypted information. Here we declare a memory stream
            ' for this purpose.
            Dim encryptedStream As MemoryStream = New MemoryStream()
            Dim cryptStream As CryptoStream = New CryptoStream(encryptedStream, cryptoTransformE, CryptoStreamMode.Write)

            ' Write the encrypted information to the stream. Flush the information
            ' when done to ensure everything is out of the buffer.
            cryptStream.Write(inputInBytes, 0, inputInBytes.Length)
            cryptStream.FlushFinalBlock()
            encryptedStream.Position = 0

            ' Read the stream back into a Byte array and return it to the calling
            ' method.
            Dim result(encryptedStream.Length - 1) As Byte
            encryptedStream.Read(result, 0, encryptedStream.Length)
            cryptStream.Close()
            encryptedStream.Close()

            Return result

        End Function

        Public Function Decrypt(ByVal instr As String) As String

            ' UTFEncoding is used to transform the decrypted Byte Array
            ' information back into a string.
            Dim inputInBytes() As Byte = UTF8.GetBytes(instr)

            ' Provide a memory stream to decrypt information into
            Dim decryptedStream As MemoryStream = New MemoryStream()
            Dim cryptStream As CryptoStream = New CryptoStream(decryptedStream, cryptoTransformD, CryptoStreamMode.Write)
            cryptStream.Write(inputInBytes, 0, inputInBytes.Length)
            cryptStream.FlushFinalBlock()
            decryptedStream.Position = 0

            ' Read the memory stream and convert it back into a string
            Dim result(decryptedStream.Length - 1) As Byte
            decryptedStream.Read(result, 0, decryptedStream.Length)

            cryptStream.Close()
            decryptedStream.Close()

            Return UTF8.GetString(result)

        End Function

        Public Function DecryptBytes(ByVal inputInBytes() As Byte) As Byte()

            ' Provide a memory stream to decrypt information into
            Dim decryptedStream As MemoryStream = New MemoryStream()
            decryptedStream.Position = 0
            Dim cryptStream As CryptoStream = New CryptoStream(decryptedStream, cryptoTransformD, CryptoStreamMode.Write)
            cryptStream.Write(inputInBytes, 0, inputInBytes.Length)
            cryptStream.FlushFinalBlock()
            decryptedStream.Position = 0

            ' Read the memory stream and convert it back into a string
            Dim result(decryptedStream.Length - 1) As Byte
            decryptedStream.Read(result, 0, decryptedStream.Length)

            cryptStream.Close()
            decryptedStream.Close()

            Return result

        End Function

#Region "IDisposable Support"
        Private disposedValue As Boolean ' To detect redundant calls

        ' IDisposable
        Protected Overridable Sub Dispose(disposing As Boolean)
            If Not Me.disposedValue Then
                If disposing Then
                    ' dispose managed state (managed objects).
                    cryptoTransformD.Dispose()
                    cryptoTransformE.Dispose()
                End If

                ' free unmanaged resources (unmanaged objects) and override Finalize() below.
                ' set large fields to null.
            End If
            Me.disposedValue = True
        End Sub

        ' TODO: override Finalize() only if Dispose(ByVal disposing As Boolean) above has code to free unmanaged resources.
        'Protected Overrides Sub Finalize()
        '    ' Do not change this code.  Put cleanup code in Dispose(ByVal disposing As Boolean) above.
        '    Dispose(False)
        '    MyBase.Finalize()
        'End Sub

        ' This code added by Visual Basic to correctly implement the disposable pattern.
        Public Sub Dispose() Implements IDisposable.Dispose
            ' Do not change this code.  Put cleanup code in Dispose(disposing As Boolean) above.
            Dispose(True)
            GC.SuppressFinalize(Me)
        End Sub
#End Region

    End Class

End Namespace
